package com.leo.boot.web.vo;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.leo.boot.web.exception.BusinessException;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NonNull;
import lombok.experimental.Accessors;
import org.springframework.data.domain.Page;

import java.util.List;
import java.util.Objects;

import static com.leo.boot.web.vo.ResultStatus.INTERNAL_SERVER_ERROR;
import static com.leo.boot.web.vo.ResultStatus.OK;

@ApiModel("结果集")
@JsonInclude(Include.NON_NULL)
@Accessors(chain = true)
@Data(staticConstructor = "of")
public class ResultVO<T> {

    @ApiModelProperty("状态码")
    @NonNull
    Integer code;

    @ApiModelProperty("状态信息")
    @NonNull
    String message;

    @ApiModelProperty("数据")
    T data;

    @ApiModelProperty("分页参数")
    Meta meta;

    @ApiModelProperty("错误信息")
    Object error;

    public static <T> ResultVO<T> result(Status status) {
        return of(status.getCode(), status.getMessage());
    }

    public static <T> ResultVO<T> result(Status status, T data) {
        return ResultVO.<T>of(status.getCode(), status.getMessage()).setData(data);
    }

    public static <T> ResultVO<List<T>> result(Status status, Page<T> page) {
        return ResultVO.<List<T>>of(status.getCode(), status.getMessage())
                .setData(page.getContent())
                .setMeta(Meta.of(
                        page.getNumber(),
                        page.getSize(),
                        page.getTotalElements()
                ));
    }

    public static ResultVO<Void> error(Status status, Object error) {
        return ResultVO.<Void>of(status.getCode(), status.getMessage()).setError(error);
    }

    public static <T> boolean isOk(ResultVO<T> resultVO) {
        return Objects.equals(resultVO.code, OK.getCode());
    }

    public T orElse(T other) {
        return isOk(this) ? data : other;
    }

    public T orElseThrow() {
        if (isOk(this)) {
            throw new BusinessException(INTERNAL_SERVER_ERROR, this);
        }
        return data;
    }

    @Accessors(chain = true)
    @Data(staticConstructor = "of")
    public static class Meta {

        @ApiModelProperty("当前页码")
        @NonNull
        Integer page;

        @ApiModelProperty("每页条数")
        @NonNull
        Integer size;

        @ApiModelProperty("总条数")
        @NonNull
        Long total;
    }
}
